package com.aispeech.astools.view;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;
import com.aispeech.astools.R;
import com.aispeech.astools.jni.NativeCall;
import com.aispeech.astools.jni.NativeCall.JniCallback;
import com.aispeech.astools.recorder.BaseRecord;
import com.aispeech.astools.recorder.BulkRecord;
import com.aispeech.astools.recorder.InterruptRecord;
import com.aispeech.astools.recorder.RecordListener;
import com.aispeech.astools.recorder.UacRecord;
import com.aispeech.astools.utils.AudioFileWrite;
import com.aispeech.astools.utils.UsbCommUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import androidx.appcompat.app.AppCompatActivity;

public class RecordActivity extends AppCompatActivity implements OnClickListener, OnItemSelectedListener, OnCheckedChangeListener {

    private final static String TAG = "RecordActivity";

//    private final int VID = 4310;
//    private final int PID = 45830;

    // 3308 vid=0x2207,pid=0x0019
    private final int VID = 8711;
    private final int PID = 25;

    private boolean mIsFeedNative = false;

    private Button mBtnStart, mBtnStop;
    private Spinner mSpRecordTypes;
    private ListView mLvInfo;
    private BaseAdapter mLvAdapter;
    private Switch mSw;
    private TextView mTvDevInfo;

    private List<String> mInfoList = new ArrayList<>();

    private BaseRecord mCurrentRecord;
    private List<BaseRecord> mRecordList = new ArrayList<>();
    private RecordListener mListener;

    private AudioFileWrite mAudioFile;
    private final String externalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
    private final String AudioFilePath = externalStorageDirectory + File.separator + "aispeech" + File.separator + "onBuffer.pcm";

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_record);

        initRecord();

        initView();

        mAudioFile = new AudioFileWrite(getApplication());

        showInfo("registerCallbackToJni ");

        //show device info
        mTvDevInfo.setText(UsbCommUtils.dumpDeviceInfo(UsbCommUtils.getUsbDevice(getApplication(), VID, PID)));

        NativeCall.registerCallbackToJni(new JniCallback() {
            @Override
            public void onBuf(byte[] array) {
                mAudioFile.writeBuffer(array);
            }

            @Override
            public void onEvent(int keyCode, int event) {
                Log.d(TAG, "onEvent with: keyCode = " + keyCode + ", event = " + event + "");
                showInfo("get key code = " + keyCode + " evnet = " + event);
            }
        });
    }

    private void initRecord() {
        mListener = new MyListener();
        UacRecord uacRecord = new UacRecord();
        BulkRecord bulkRecord = new BulkRecord(VID, PID);
        InterruptRecord interruptRecord = new InterruptRecord(VID, PID);

        mRecordList.add(uacRecord);
        mRecordList.add(interruptRecord);
        mRecordList.add(bulkRecord);
    }

    private void initView() {
        mBtnStart = findViewById(R.id.btn_start);
        mBtnStop = findViewById(R.id.btn_stop);
        mSpRecordTypes = findViewById(R.id.sp_record_type);
        mLvInfo = findViewById(R.id.lv_infos);
        mSw = findViewById(R.id.sw_feed_native);
        mTvDevInfo = findViewById(R.id.tv_dev_info);

        mBtnStart.setOnClickListener(this);
        mBtnStop.setOnClickListener(this);
        mSpRecordTypes.setOnItemSelectedListener(this);
        mSw.setOnCheckedChangeListener(this);

        mLvAdapter = new LvAdapter();
        mLvInfo.setAdapter(mLvAdapter);
    }

    private void showInfo(final String info) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mInfoList.add(info);
                mLvAdapter.notifyDataSetChanged();
                mLvInfo.setSelection(mInfoList.size() - 1);
            }
        });
    }

    private void startRecord() {
        if (null != mCurrentRecord) {
            showInfo("start record: path = " + AudioFilePath);
            mAudioFile.startWrite(AudioFilePath);
            mCurrentRecord.start();
        }
    }

    private void stopRecord() {
        if (null != mCurrentRecord) {
            showInfo("stop record");
            mAudioFile.closeWrite();
            mCurrentRecord.stop();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        startRecord();
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopRecord();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != mCurrentRecord) {
            mCurrentRecord.destroy();
            mCurrentRecord = null;
        }

        if (null != mRecordList) {
            mRecordList.clear();
            mRecordList = null;
        }
    }

    @Override
    public void onClick(View view) {
        if (mBtnStart == view) {
            Log.d(TAG, "onClick with: start");
            startRecord();
        } else if (mBtnStop == view) {
            Log.d(TAG, "onClick with: stop");
            stopRecord();
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> adapterView, View view, int index, long l) {
        Log.d(TAG, "onItemSelected with: index = " + index);
        if (null != mRecordList && mRecordList.size() >= index) {
            if (mCurrentRecord != mRecordList.get(index)){
                if (null != mCurrentRecord) {
                    mCurrentRecord.stop();
                    mCurrentRecord.destroy();
                }
                mCurrentRecord = mRecordList.get(index);
                mCurrentRecord.init(getApplication(), mListener);
            }
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> adapterView) {
        Log.d(TAG, "onNothingSelected: ");
    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        Log.d(TAG, "onCheckedChanged with:  isChecked = " + isChecked + "");
        mIsFeedNative = isChecked;
    }

    public String byteToStr(byte[] buffer) {
        try {
            int length = 0;
            for (int i = 0; i < buffer.length; ++i) {
                if (buffer[i] == 0) {
                    length = i;
                    break;
                }
            }
            return new String(buffer, 0, length, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }


    private class MyListener implements RecordListener {

        @Override
        public void onBuffer(byte[] data) {
            try {
//                Log.d(TAG, "onBuffer with: data = " + byteToStr(data) + "");
                //if you need decode data use native lib
                //you can call feedBufToJNI, and process in native-lib.cpp
                //than get buf after process from JniCallback#onBuf
                if (mIsFeedNative) {
                    NativeCall.feedBufToJNI(data, data.length);
                } else {
                    mAudioFile.writeBuffer(data);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onEvent(EVENT event) {
            Log.d(TAG, "onEvent with: event = " + event + "");
            showInfo("record event " + event);
        }

        @Override
        public void onError(String info) {
            Log.e(TAG, "onError with: info = " + info + "");
            showInfo(info);
        }
    }

    private class LvAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return mInfoList == null ? 0 : mInfoList.size();
        }

        @Override
        public Object getItem(int i) {
            if (null != mInfoList) {
                mInfoList.get(i);
            }
            return null;
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View convertView, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            if (convertView == null) {
                convertView = RecordActivity.this.getLayoutInflater().inflate(R.layout.lv_info_item, null);
                viewHolder = new ViewHolder(convertView);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            viewHolder.tvInfo.setText(mInfoList.get(i));
            return convertView;
        }
    }

    private final class ViewHolder {
        TextView tvInfo;
        ViewHolder(View view) {
            tvInfo = view.findViewById(R.id.tv_info);
        }
    }

}
